Graphics Programming using Allegro

Servicing the Mouse

Published:  September 17, 2008
by Richard G. Baldwin

File:  Allegro00155


Preface

General

This lesson is part of a series (see Resources) designed to teach you how to use Allegro to do graphics programming in C++.  My purpose in writing the series is to provide lecture and lab material for a course titled Game Development Using C++ that I teach at Austin Community College in Austin, Texas.  However, if you have stumbled upon this series and you find it useful, you are welcome to study it.

Viewing tip

I recommend that you open another copy of this document in a separate browser window and use the following links to easily find and view the figures and listings while you are reading about them.

Figures

Listings

Supplemental material

I recommend that you also study the other lessons in my extensive collection of online programming tutorials.  You will find a consolidated index at www.DickBaldwin.com.

Preview

This program shows how to write code that will respond when the user presses either the left or right mouse button while pointing to an Allegro graphics window.

The program displays a black 440x500 graphics window as shown in Figure 1.

Figure 1. Screen output from the program named Mouse01.

Press the left mouse button

Pointing to the black area and pressing the left mouse button causes the mouse pointer to disappear and causes a red filled circle to be drawn at the location of the mouse pointer.  Several such circles are shown in the upper-left portion of Figure 1.

In all cases, releasing the mouse button causes the mouse pointer to reappear.

Press the right mouse button

Pointing to the black area and pressing the right mouse button causes the mouse pointer to disappear and causes a green filled circle to be drawn at the location of the mouse pointer.  Several such circles are shown in the upper-right portion of Figure 1.

Drag the mouse with a button pressed

Dragging slowly while the right or left mouse button is pressed produces a wide red or green line (depending on which button is pressed) that traces out the path of the mouse pointer.  Two such lines are shown in the center portion of Figure 1.

Dragging rapidly with a mouse button pressed may produce a non-uniform sequence of red or green filled circles that trace out the path of the mouse pointer.  This is illustrated by the red and green circles at the bottom of Figure 1.

Terminating the program

Pressing the Esc key causes the program to terminate.

Discussion and sample code

Will explain in fragments

As is my custom, I will explain this program in fragments.  A complete listing of the program is provided in Listing 6 near the end of the lesson.

This program consists of the main function plus two other functions named mouseInfo and draw.  The program was designed to avoid the use of global variables.

Beginning of the main function

I will start by explaining the main function, which begins in Listing 1.

Listing 1. Beginning of the main function.
int main(){
  //NOTE THE USE OF LOCAL VARIABLES IN PLACE OF GLOBALS
  BITMAP* screenBuf = NULL;
  int xCoor = 0;
  int yCoor = 0;
  int color = 0;

  allegro_init();
  install_mouse();
  install_keyboard();
  set_color_depth(32);
  set_gfx_mode(GFX_AUTODETECT_WINDOWED,440,500,0,0);
  screenBuf = create_bitmap(440,500);
  show_mouse(screen);

There are two statements in Listing 1 that I haven't explained in earlier lessons (see Resources):

The install_mouse function

The documentation for the install_mouse reads partially as shown in Figure 2.

Figure 2. Partial description of the install_mouse function.
Installs the Allegro mouse handler. You must do this before using any other mouse functions. Returns -1 on failure, zero if the mouse handler is already installed (in which case this function does nothing)...

The show_mouse function

As you have probably already guessed, the call to the show_mouse function in Listing 1 tells Allegro to display a mouse pointer on the graphics window.  As you will see later, a call to the show_mouse function passing NULL as a parameter hides the mouse pointer.

The documentation for show_mouse contains some cautions, so you should review that documentation before calling this function.

The animation loop

The animation loop is shown in Listing 2, which contains a pair of nested while loops.  The outer loop continues to iterate until the user presses the Esc key, at which time the program terminates.

Listing 2. The animation loop.
  while(!key[KEY_ESC]){
    while(mouseInfo(&xCoor,&yCoor,&color)){
      //Draw while mouse button is down.
      draw(xCoor,yCoor,screenBuf,color);
    }//end while
  }//end while

  return 0;
}//end main
END_OF_MAIN();

The inner loop

During each iteration of the inner loop, the conditional clause calls the mouseInfo function.  This function returns true if a left or right mouse button is pressed and returns false if no mouse buttons are pressed.  (This program does not attempt to service the middle button, a mouse wheel, etc.)

If the mouseInfo function returns true, the body of the inner loop in Listing 2 is executed, calling the draw function to draw the filled circles shown in Figure 1.

Beginning of the mouseInfo function

The mouseInfo function receives three pointers of type int.  As you can see from the call to the mouseInfo function in Listing 2, each of these parameters points to one of the local variables having the same name that was declared in Listing 1.  During each execution of the function, the coordinates of the mouse pointer and sometimes a color value for red or green will be stored indirectly in those variables.

The mouseInfo function begins in Listing 3.

Listing 3. Beginning of the mouseInfo function.
bool mouseInfo(int *xCoor,int *yCoor,int *color){
  //Get current mouse coordinates and send back via
  // pointer variables.
  *xCoor = mouse_x;
  *yCoor = mouse_y;
  

The mouse_x and mouse_y variables

Apparently mouse_x and mouse_y are global variables that are made available to the program by the header file named allegro.h.

Although the documentation doesn't have a lot to say on the subject, accessing mouse_x and mouse_y in Listing 3 returns the horizontal and vertical coordinates of the mouse pointer relative to the upper-left corner of the black graphics window in Figure 1.

As mentioned above, Listing 3 uses the first two pointers received as parameters to store the coordinate values in the local variables in the main function declared in Listing 2.

Completion of the mouseInfo function

The mouse_b function that is called twice in Listing 4 returns 0 (false) if a mouse button is not pressed when the function is called.

Listing 4. Completion of the mouseInfo function.
  //Test for a mouse button pressed. Set drawing color
  // based on left or right mouse button.
  if(mouse_b & 1){//left mouse button
    *color = makecol(255,0,0);//red
    return true;//signal the requirement to draw
  }else if(mouse_b & 2){//right button
    *color = makecol(0,255,0);//green
    return true;
  }else{//no button
    return false;//no drawing required
  }//end else
}//end mouseInfo

The return value when a button is pressed

If the left mouse button is pressed when the mouse_b function is called, it returns a 1.  If the right mouse button is pressed when the function is called, it returns a 2.  (In C++, a non-zero integer value is interpreted as true.)

Test for a pressed mouse button

Listing 4 tests to determine if either button is pressed when the mouseInfo function is called.  If both calls to mouse_b return 0, Listing 4 returns false, causing the body of the inner loop in Listing 2 to be skipped during the current iteration.

Behavior when a mouse button is pressed

If either mouse button is pressed, the code in Listing 4 determines which button is pressed and takes the appropriate action based on that determination.  If the left mouse button is pressed, Listing 4 stores the color value for red indirectly into the local variable named color in Listing 1.  If the right mouse button is pressed (and the left mouse button is not pressed), Listing 4 stores the color value for green indirectly into the local variable named color in Listing 1.  (If both mouse buttons are pressed, Listing 4 stores the color value for red indirectly into the local variable named color in Listing 1.)

If either button is pressed, the mouseInfo function returns true causing the draw function to be called once during the current iteration of the inner loop in Listing 2.

The draw function

As you can see in Listing 2, when the draw function is called, the coordinate and color values stored in the local variables in Listing 1 are passed as parameters.  In addition, a pointer to the off-screen buffer is also passed to the draw function.

The draw function is shown in its entirety in Listing 5.

Listing 5. The draw function.
void draw(int xCoor,int yCoor,BITMAP* buf,int color){
  show_mouse(NULL);//hide mouse pointer while drawing
  
  //Draw filled circle at mouse coor on off-screen buffer.
  circlefill(buf,xCoor,yCoor,5,color);
  //Copy the off-screen image to the screen.
  blit(buf,screen,0,0,0,0,440,500);
  
  show_mouse(screen);//show mouse when drawing finished
}//end draw

Hide the mouse pointer and draw a filled circle

Listing 5 begins by hiding the mouse pointer in order to satisfy one of the cautions mentioned earlier.

Once the mouse pointer is turned off, Listing 5 uses the values of the incoming parameters to draw a filled circle of the specified color at the specified location in the off-screen buffer.  Then Listing 5 copies the contents of the off-screen buffer to the screen.  I have explained code similar to this in numerous previous lessons (see Resources) so I won't repeat that explanation here.

Finally, Listing 5 makes the mouse pointer visible again before returning control to the main function.

Summary

You learned how to service the mouse in this lesson.  In particular, you learned how to write code that will respond when the user presses either the left or right mouse button while pointing to an Allegro graphics window.

Complete program listing

A complete listing of the program is shown in Listing 6.

Listing 6. Source code for the program named Mouse01.
/*Project Mouse01
Illustrates how to handle mouse presses and mouse drags.

The program displays a black 440x500 graphics window.

Pointing to the black area and pressing the left mouse
button causes the mouse pointer to disappear and a red
filled circle to be drawn at the location of the mouse
pointer.

Point to the black area and pressing the right mouse
button causes the mouse pointer to disappear and a green
filled circle to be drawn at the location of the mouse
pointer.

Dragging slowly with the right or left mouse button
pressed produces a wide red or green line (depending on
which button is pressed) that traces out the path of the
mouse pointer.

Dragging rapidly with a mouse button pressed may produce
a non-uniform sequence of red or green filled circles
that trace out the path of the mouse pointer.

Releasing the mouse button causes the mouse pointer to
reappear.

Pressing the Esc key causes the program to terminate.
********************************************************/
#include <allegro.h>
//LOOK! NO GLOBAL VARIABLES

bool mouseInfo(int *xCoor,int *yCoor,int *color){
  //Get current mouse coordinates and send back via
  // pointer variables.
  *xCoor = mouse_x;
  *yCoor = mouse_y;
  
  //Test for a mouse button pressed. Set drawing color
  // based on left or right mouse button.
  if(mouse_b & 1){//left mouse button
    *color = makecol(255,0,0);//red
    return true;//signal the requirement to draw
  }else if(mouse_b & 2){//right button
    *color = makecol(0,255,0);//green
    return true;
  }else{//no button
    return false;//no drawing required
  }//end else
}//end mouseInfo
//------------------------------------------------------//

void draw(int xCoor,int yCoor,BITMAP* buf,int color){
  show_mouse(NULL);//hide mouse pointer while drawing
  
  //Draw filled circle at mouse coor on off-screen buffer.
  circlefill(buf,xCoor,yCoor,5,color);
  //Copy the off-screen image to the screen.
  blit(buf,screen,0,0,0,0,440,500);
  
  show_mouse(screen);//show mouse when drawing finished
}//end draw
//------------------------------------------------------//

int main(){
  //NOTE THE USE OF LOCAL VARIABLES IN PLACE OF GLOBALS
  BITMAP* screenBuf = NULL;
  int xCoor = 0;
  int yCoor = 0;
  int color = 0;

  allegro_init();
  install_mouse();
  install_keyboard();
  set_color_depth(32);
  set_gfx_mode( GFX_AUTODETECT_WINDOWED,440,500,0,0);
  screenBuf = create_bitmap(440,500);
  show_mouse(screen);

  while(!key[KEY_ESC]){
    while(mouseInfo(&xCoor,&yCoor,&color)){
      //Draw while mouse button is down.
      draw(xCoor,yCoor,screenBuf,color);
    }//end while
  }//end while

  return 0;
}//end main
END_OF_MAIN();

 

Resources


Copyright

Copyright 2008, Richard G. Baldwin.  Reproduction in whole or in part in any form or medium without express written permission from Richard Baldwin is prohibited.

About the author

Richard Baldwin is a college professor (at Austin Community College in Austin, TX) and private consultant whose primary focus is a combination of Java, C#, and XML. In addition to the many platform and/or language independent benefits of Java and C# applications, he believes that a combination of Java, C#, and XML will become the primary driving force in the delivery of structured information on the Web.

Richard has participated in numerous consulting projects and he frequently provides onsite training at the high-tech companies located in and around Austin, Texas.  He is the author of Baldwin's Programming Tutorials, which have gained a worldwide following among experienced and aspiring programmers. He has also published articles in JavaPro magazine.

In addition to his programming expertise, Richard has many years of practical experience in Digital Signal Processing (DSP).  His first job after he earned his Bachelor's degree was doing DSP in the Seismic Research Department of Texas Instruments.  (TI is still a world leader in DSP.)  In the following years, he applied his programming and DSP expertise to other interesting areas including sonar and underwater acoustics.

Richard holds an MSEE degree from Southern Methodist University and has many years of experience in the application of computer technology to real-world problems.

Baldwin@DickBaldwin.com

-end-